import os

from flask import Flask, render_template

# 创建app应用,__name__是python预定义变量，被设置为使用本模块
from flask_admin import Admin
from flask_bootstrap import Bootstrap
from flask_debugtoolbar import DebugToolbarExtension
from flask_login import LoginManager
from flask_restful import Api

import models
from admin import MyModelView, UserView
from app_response import JSONResponse
from custom_command import user_cli
from models import db
from views.order import order
from views.other import other
from views.rest_user import RestUser
from views.user import user, mail, signal

app = Flask(__name__)
bootstrap = Bootstrap(app)
app.debug = True  # 开启debug
app.response_class = JSONResponse  # 指定返回类,解析json
# 注册蓝图
app.register_blueprint(other, url_prefix='/other')
app.register_blueprint(user, url_prefix='/user')
app.register_blueprint(order, url_prefix='/order')
# 配置mysql
#app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+mysqlconnector://root:123456@localhost:3306/flask?charset=utf8"
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:123456@localhost:3306/flask?charset=utf8'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True  # 为True时请求结束自动提交到数据库
app.config['SQLALCHEMY_RECORD_QUERIES'] = True  # debug中显示当前请求sql
db.init_app(app)

# 配置邮件发送服务,qqMail
app.config['MAIL_SERVER'] = 'smtp.qq.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USE_TLS'] = False
# 配置默认发送人
app.config['MAIL_DEFAULT_SENDER'] = os.environ.get('MAIL_USERNAME')
# 敏感信息放入环境变量中读取,不要直接写在代码中
app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME')
app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD')  # 这里是邮箱客户端授权码
# 初始化mail
mail.init_app(app)
# 注册restful api
api = Api(app)
api.add_resource(RestUser, '/rest/<int:id>', '/rest/<name>')  # 可使用多个url访问接口
# 在flask shell 中导入其他对象
@app.shell_context_processor
def make_shell_context():
    return dict(models=models, db=db)


@app.errorhandler(404)
def page_not_found(e):
    return render_template('error.html', e=e), 404


@app.errorhandler(500)
def server_error(e):
    return render_template('error.html', e=e), 500


# Flask-Mail 中的 send() 函数使用 current_app ，因此必须激活程序上下文。
# 不过，在不同线程中执行 mail.send() 函数时，程序上下文要使用 app.app_context() 人工创建
@signal.connect  # 可以直接通过注解绑定函数
def send_async_email(msg):
    print("---开始发送---")
    with app.app_context():
        mail.send(msg)


# 添加自定义命令
app.cli.add_command(user_cli)


# 配置debugToolbar
toolbar = DebugToolbarExtension()
app.config['SECRET_KEY'] = 'hou'
app.config['DEBUG_TB_INTERCEPT_REDIRECTS'] = False  # 不拦截重定向
toolbar.init_app(app)


# 初始化admin后台管理
admin = Admin(app, name='MyWebSite', template_mode='bootstrap3')
# 注册模型用来管理,可自定义url,避免冲突(此处也使用蓝图,名字默认使用model的小写名字,名字不能与蓝图名字冲突)
admin.add_view(MyModelView(models.User, db.session, name=u'用户管理', url='user/manage'))
admin.add_view(UserView(name='自定义视图'))


# 配置flask-login
login_manager = LoginManager()
login_manager.login_view = 'myuser.login' # 指定跳转登录函数,权限拦截时跳转
login_manager.login_message_category = 'info'
login_manager.login_message = '请先登录'
login_manager.init_app(app)

# 配置回调函数,必须配置
# user session 记录的是用户 ID (user_id)，回调函数的作用就是通过 user_id 返回对应的 User 对象
@login_manager.user_loader
def load_user(user_id):
    print(user_id)  # 登录成功的时候会自动获取主键id
    return models.User.query.filter_by(id=user_id).first()


if __name__ == '__main__':
    app.run(port=8080)  # 端口默认5000
